/*
 * SchulzeFileParser.java
 *
 * Copyright (C) 2014 Fabian Wenzelmann
 *
 * This file is part of stura_voting.
 *
 * stura_voting is free software: you
 * can redistribute it and/or modify it under the terms of the
 * GNU General Public License as published by the Free Software Foundation,
 * either version 3 of the License, or (at your option) any later version.
 *
 * stura_voting is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
 * Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with stura_voting.
 *
 * If not, see <http://www.gnu.org/licenses/>.
 */
 
package de.stura.schulze;
 
import de.stura.WeightedVoter;

import java.io.BufferedReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;

public class SchulzeFileParser {
    
    public SchulzeFileParser() {
        ;
    }
    
    // TODO: add absolute majority
    public ArrayList<SchulzeEvaluator> parse(BufferedReader br,
        HashMap<String, WeightedVoter> weights, SchulzeWarningHandler handler) throws IOException, SchulzeParseException {
        // first we expect the first line where we find all the names
        String line = br.readLine();
        if (line == null) {
            throw new SchulzeParseException("File does not have content.");
        }
        // actually we ignore the first element of this in the following
        // because it should be an empty string
        String[] names = line.split("\t");
        ArrayList<SchulzeEvaluator> res = new ArrayList<SchulzeEvaluator>(Math.min(0, names.length - 1));
        
        // in the next line we assume all the choices separated by ","
        line = br.readLine();
        if (line == null) {
            throw new SchulzeParseException("File must contain a second line containing the choices, " +
                "separated by \",\".");
        }
        String[] allChoices = line.split("\t");
        if (allChoices.length != names.length) {
            throw new SchulzeParseException("Found " + names.length + " votings but only for " + allChoices.length +
                " choices are provided.");
        }
        for (int i = 1; i < allChoices.length; ++i) {
            String[] choices = allChoices[i].split(",");
            for (int j = 0; j < choices.length; ++j) {
                choices[j] = choices[j].trim();
            }
            if (choices.length == 0) {
                throw new SchulzeParseException("Found voting without choices in voting number " + i);
            }
            res.add(new SchulzeEvaluator(choices));
        }
        
        
        line = null;
        int lineNum = 2;
        // now we expect to find all voters (name) and then the votes for each subject
        while ((line = br.readLine()) != null) {
            ++lineNum;
            line = line.trim();
            if (line.startsWith("#")) {
                continue;
            }
            String[] split = line.split("\t");
            if (split.length == 0) {
                // TODO: check what happens if we find just the name and nothing else
                handler.addWarningText("Keine Eingabe gefunden in Zeile " + lineNum + ".");
                continue;
            }
            String name = split[0];
            WeightedVoter v = weights.get(name);
            if (v == null) {
                handler.voterNotFound(name, lineNum);
                continue;
            }
            // after the name we expect all the votes, if we have more than we expect we add a warning
            if(split.length > names.length) {
                handler.addWarningText("\"" + name + "\" hat zu viele Stimmen abgegeben, verwendet werden nur die ersten.");
            }
            int weight = v.getWeight();
            int num = Math.min(names.length, split.length);
            for (int i = 1; i < num; ++i) {
                String text = split[i].trim();
                SchulzeEvaluator s = res.get(i - 1);
                ArrayList<SchulzeVote> schulzeVote = s.fromString(text);
                for (int j = 0; j < v.getWeight(); ++j) {
                    s.addVote(schulzeVote);
                }
            }
        }
        handler.handle();
        return res;
    } 
    
}
